﻿#if defined _MSC_VER && !defined _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS // 禁用 C4996 安全警告
#endif // _MSC_VER
#include "MySHA256.h"

// 定义 SHA-256 算法中使用的常数
static const uint32_t k[64] = {
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e56af, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

// 定义初始哈希值
static const uint32_t h_initial[8] = {
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};

// 定义一些辅助函数
// 右旋操作：将 x 右旋 n 位，左 1 边空出的部分用 x 的左边部分填充
#define ROTATE_RIGHT(x, n) ((x >> n) | (x << (32 - n)))
// 选择操作：如果 x 为 1，则选择 y；如果 x 为 0，则选择 z
#define CH(x, y, z) ((x & y) ^ (~x & z))
// 多数操作：如果 x、y、z 中至少有两个为 1，则结果为 1；否则结果为 0
#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
// SIGMA0操作：SHA-256 算法中的非线性函数，用于处理消息扩展
#define SIGMA0(x) (ROTATE_RIGHT(x, 2) ^ ROTATE_RIGHT(x, 13) ^ ROTATE_RIGHT(x, 22))
// SIGMA1操作：SHA-256 算法中的非线性函数，用于处理消息扩展
#define SIGMA1(x) (ROTATE_RIGHT(x, 6) ^ ROTATE_RIGHT(x, 11) ^ ROTATE_RIGHT(x, 25))
// sigma0操作：SHA-256 算法中的非线性函数，用于处理消息压缩
#define sigma0(x) (ROTATE_RIGHT(x, 7) ^ ROTATE_RIGHT(x, 18) ^ (x >> 3))
// sigma1操作：SHA-256 算法中的非线性函数，用于处理消息压缩
#define sigma1(x) (ROTATE_RIGHT(x, 17) ^ ROTATE_RIGHT(x, 19) ^ (x >> 10))


// 将32位整数转换为大端字节序
static void uint32_to_be_bytes(uint32_t word, uint8_t* bytes)
{
    bytes[0] = (word >> 24) & 0xff;
    bytes[1] = (word >> 16) & 0xff;
    bytes[2] = (word >> 8) & 0xff;
    bytes[3] = word & 0xff;
}

// 将大端字节序转换为 32 位整数
static inline uint32_t be_bytes_to_uint32(const uint8_t* bytes)
{
    return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
}

// 填充数据
static void pad_data(const uint8_t* input, size_t length, uint8_t* padded, size_t* padded_length)
{
    size_t new_length = (length + 8) % SHA256_BLOCK_SIZE == 0 ? length + 8 : ((length + 8) / SHA256_BLOCK_SIZE + 1) * SHA256_BLOCK_SIZE;
    memset(padded, 0, new_length);
    memcpy(padded, input, length);
    padded[length] = 0x80;
    uint64_t bit_length = length * 8;
    uint32_to_be_bytes((uint32_t)(bit_length >> 32), padded + new_length - 8);
    uint32_to_be_bytes((uint32_t)bit_length, padded + new_length - 4);
    *padded_length = new_length;
}

// 计算 SHA-256
static void sha256(const uint8_t* input, size_t length, uint8_t* output)
{
#if defined(_MSC_VER)
    // MSVC 使用 malloc() 函数分配内存，需要包含 stdlib.h 头文件
    size_t padded_size = SHA256_BLOCK_SIZE * (length / SHA256_BLOCK_SIZE + 3);
    uint8_t* padded = (uint8_t*)malloc(padded_size); // 动态分配内存
    if (padded == NULL) {
        // 处理内存分配失败的情况
        return;
    }
#else
    // 支持可变长数组的编译器实现如下：
    uint8_t padded[SHA256_BLOCK_SIZE * (length / SHA256_BLOCK_SIZE + 3)];
#endif
    size_t padded_length;
    pad_data(input, length, padded, &padded_length);

    uint32_t h[8];
    memcpy(h, h_initial, sizeof(h_initial));

    for (size_t i = 0; i < padded_length; i += SHA256_BLOCK_SIZE) {
        uint32_t w[64];
        for (size_t j = 0; j < 16; j++) {
            w[j] = be_bytes_to_uint32(padded + i + j * 4);
        }
        for (size_t j = 16; j < 64; j++) {
            w[j] = sigma1(w[j - 2]) + w[j - 7] + sigma0(w[j - 15]) + w[j - 16];
        }

        uint32_t a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], h_val = h[7];

        for (size_t j = 0; j < 64; j++) {
            uint32_t T1 = h_val + SIGMA1(e) + CH(e, f, g) + k[j] + w[j];
            uint32_t T2 = SIGMA0(a) + MAJ(a, b, c);
            h_val = g;
            g = f;
            f = e;
            e = d + T1;
            d = c;
            c = b;
            b = a;
            a = T1 + T2;
        }

        h[0] += a;
        h[1] += b;
        h[2] += c;
        h[3] += d;
        h[4] += e;
        h[5] += f;
        h[6] += g;
        h[7] += h_val;
    }

    for (size_t i = 0; i < 8; i++) {
        uint32_to_be_bytes(h[i], output + i * 4);
    }
#if defined(_MSC_VER)
    // MSVC 需要 free()
    free(padded); // 释放动态分配的内存
#endif
}

// 将哈希值转换为十六进制字符串
static void hash_to_hex_string(const uint8_t* hash, size_t length, char* hex_string)
{
    static const char hex_chars[] = "0123456789abcdef";
    size_t hex_length = length * 2; // 每个字节对应两个十六进制字符

    for (size_t i = 0; i < length; i++) {
        hex_string[i * 2] = hex_chars[(hash[i] >> 4) & 0xf];
        hex_string[i * 2 + 1] = hex_chars[hash[i] & 0xf];
    }

    hex_string[hex_length] = '\0'; // 添加字符串结束符
}

char sha256_file_init(sha256_fileCtx* fileCtx, size_t once_size, uint64_t position)
{
    if (fileCtx == NULL) {
        // 处理参数为空的情况
        return INPUT_ERROR;
    }
    //FILE* file = fopen(filename, "rb");
    //if (file == NULL) {
    //    // 处理打开文件失败的情况
    //    return FILE_ERROR;
    //}
    if (once_size == 0) {
        // 处理一次性读取文件的情况
        once_size = DEFAULT_ONCE_SIZE; // 默认一次读取 2MB 数据
    }
    fileCtx->file_position_ = position;
    if (position == 0) {
        // 初始化 hash_str_ 为初始哈希值的十六进制表示
        static const char initial_hash_str[] = "6a09e667bb67ae853c6ef372a54ff53a510e527f9b05688c1f83d9ab5be0cd19";
        strncpy(fileCtx->hash_str_, initial_hash_str, SHA256_DIGEST_SIZE * 2 + 1);
    }
    fileCtx->once_size_ = once_size;

    // 统一使用 malloc() 函数分配内存，这是因为多线程中如果使用静态变量（可变长数组需要 static）存在数据竞争问题
    fileCtx->file_buffer_ = (char*)malloc(once_size); // 动态分配内存，需要包含 stdlib.h 头文件
    if (fileCtx->file_buffer_ == NULL) {
        // 处理内存分配失败的情况
        //fclose(file);
        return FILE_ERROR;
    }
    fileCtx->file_buffer_copy_ = fileCtx->file_buffer_;
    // 读取文件大小
    //fseek(file, 0, SEEK_END);
    //fileCtx->file_size_ = ftell(file);
    // 关闭文件
    //if (fclose(file) != 0) {
    //    // 处理关闭文件失败的情况
    //    free(fileCtx->file_buffer_);
    //    return FILE_ERROR;
    //}
    fileCtx->buf_index_ = 0;
    return IS_OK; // 成功初始化
}

void free_sha256_fileCtx(sha256_fileCtx* fileCtx)
{
    if (fileCtx->file_buffer_) // 必须 free()
        free(fileCtx->file_buffer_); // 释放动态分配的内存
    fileCtx->file_buffer_ = NULL;
    //fileCtx->file_size_ = 0;
    fileCtx->once_size_ = 0;
    fileCtx->file_position_ = 0;
    memset(fileCtx->hash_str_, 0, SHA256_DIGEST_SIZE * 2 + 1); // 重置哈希值字符串为初始值
    memset(fileCtx->hash_str_buf_, 0, MAX_BUFFER);
    fileCtx->buf_index_ = 0;
}

const char* strn_to_sha256(const char* input, size_t length)
{
    if (input == NULL)
        return NULL; // 处理空字符串的情况
    uint8_t hash[SHA256_DIGEST_SIZE];
    static const char static_hex_strn[SHA256_DIGEST_SIZE * 2 + 1]; // 额外的1是为了存储字符串结束符
    sha256((const uint8_t*)input, length, hash);
    hash_to_hex_string(hash, SHA256_DIGEST_SIZE, static_hex_strn);
    return static_hex_strn;
}

const char* string_to_sha256(const char* input)
{
    if (input == NULL)
        return NULL; // 处理空字符串的情况
    uint8_t hash[SHA256_DIGEST_SIZE];
    static const char static_hex_string[SHA256_DIGEST_SIZE * 2 + 1]; // 额外的1是为了存储字符串结束符
    sha256((const uint8_t*)input, strlen(input), hash);
    hash_to_hex_string(hash, SHA256_DIGEST_SIZE, static_hex_string);
    return static_hex_string;
}

// 计算字符串的 SHA-256 值，结果覆盖传入的 SHA-256 哈希值字符串
static inline void string_to_sha256_inner(char hex_str[SHA256_BLOCK_SIZE + 1],
    const char* input,
    size_t length) // 这里是 input 字符串前 length 长度
{
    uint8_t hash[SHA256_DIGEST_SIZE];
    sha256((const uint8_t*)input, length, hash);
    hash_to_hex_string(hash, SHA256_DIGEST_SIZE, hex_str);
}

// 辅助函数，计算两个 SHA-256 哈希值字符串的 SHA-256 哈希值字符串，结果覆盖第一个传入的 SHA-256 哈希值字符串
static inline void two_sha256_add(char* hash_first, const char* hash_second)
{
    char tmp_hash_str[130];
    strncpy(tmp_hash_str, hash_first, 65);
    strncpy(tmp_hash_str + 65, hash_second, 65);
    string_to_sha256_inner(hash_first, tmp_hash_str, 130);
}

// 计算传入文件的 SHA-256 值
char file_sha256(sha256_fileCtx* fileCtx, const char* filename) {
    if (filename == NULL)
        return INPUT_ERROR; // 处理空文件名的情况
    FILE* file = fopen(filename, "rb");
    if (file == NULL)
        return FILE_ERROR; // 处理打开文件失败的情况

    uint8_t hash[SHA256_DIGEST_SIZE];
    char hex_string[SHA256_DIGEST_SIZE * 2 + 1]; // 额外的1是为了存储字符串结束符
    fseek(file, fileCtx->file_position_, SEEK_SET); // 跳到文件已计算哈希值的位置
    size_t read_size;
    // 读取文件数据
    while ((read_size = fread(fileCtx->file_buffer_, 1, fileCtx->once_size_, file)) > 0) {
        if (fileCtx->buf_index_ < MAX_BUFFER) {
            // 计算读取数据对应的 SHA-256 值写入 hex_string
            string_to_sha256_inner(hex_string, fileCtx->file_buffer_, read_size);

            // 添加到已计算哈希值字符串缓冲区中
            strncpy(fileCtx->hash_str_buf_ + fileCtx->buf_index_, hex_string, 65);
            fileCtx->buf_index_ += 65;
        }
        else {
            // 缓冲区已满，计算缓冲区对应的 SHA-256 值
            string_to_sha256_inner(hex_string, fileCtx->hash_str_buf_, fileCtx->buf_index_);
            // 合并 SHA-256 值
            two_sha256_add(fileCtx->hash_str_, hex_string);
            // 重置缓冲区下标
            fileCtx->buf_index_ = 0;
        }
        //if (fileCtx->file_buffer_ != fileCtx->file_buffer_copy_)
        //    __debugbreak(); // 确保 file_buffer_ 指针不指向 file_buffer_copy_ 指针

        fileCtx->file_position_ += read_size;
    }
    // 文件读取完毕之后，可能还需要一次计算剩余缓冲区对应的 SHA-256 值
    if (fileCtx->buf_index_ > 0) {
        string_to_sha256_inner(hex_string, fileCtx->hash_str_buf_, fileCtx->buf_index_);
        // 合并 SHA-256 值
        two_sha256_add(fileCtx->hash_str_, hex_string);
        // 重置缓冲区下标
        fileCtx->buf_index_ = 0;
    }
    // 关闭文件
    if (fclose(file) != 0) {
        // 处理关闭文件失败的情况
        return FILE_ERROR;
    }

    return IS_OK; // 成功计算
}


// 打印哈希值
void print_hash(const uint8_t* hash, size_t length)
{
    for (size_t i = 0; i < length; i++)
        printf("%02x", hash[i]);
    printf("\n");
}

void test_sha256()
{
    const char* input = "Hello, SHA-256!，this is a test for SHA-256 alhorithm.";
    uint8_t hash[SHA256_DIGEST_SIZE];
    char hex_string[SHA256_DIGEST_SIZE * 2 + 1]; // 额外的1是为了存储字符串结束符
    string_to_sha256_inner(hex_string, input, strlen(input));

    /*
    sha256((const uint8_t*)input, strlen(input), hash);
    hash_to_hex_string(hash, SHA256_DIGEST_SIZE,hex_string);
    */

    printf("SHA-256(\"%s\") = %s\n", input, hex_string);
}

//int main() {
//    test_sha256();
//    return 0;
//}
